/**
 * ReportGear(2011)
 */
package net.abbp.report.model.cell.style;

import java.awt.Color;
import java.awt.Font;
import java.util.Map;
import java.util.WeakHashMap;

import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;

/**
 * 字体样式
 * 
 * @version 1.0 2011-3-10
 * @author <a herf="lexloo@gmail.com">lexloo</a>
 * @since Report 1.0
 */
@XmlJavaTypeAdapter(FontStyleAdapter.class)
public class FontStyle extends Font {
    private static final long serialVersionUID = -2565844210477509379L;
    /**
     * 字体样式缓存
     */
    private static Map<FSK, FontStyle> cachedFontStyle = new WeakHashMap<FSK, FontStyle>();

    /**
     * 默认字体样式,可设置其它默认样式 如: getInstance("SimSun", 0, 12);
     */
    public static FontStyle DEFAULT_STYLE = getInstance();

    /**
     * 字体颜色
     */
    private Color foreground = Color.BLACK;
    /**
     * 下划线类型
     */
    private int underline = 0;
    /**
     * 穿透线
     */
    private boolean strikethrough = false;
    /**
     * 阴影
     */
    private boolean shadow = false;
    /**
     * 上标
     */
    private boolean superscript = false;
    /**
     * 下标
     */
    private boolean subscript = false;

    /**
     * 获取FontStyle实例
     * 
     * @return FontStyle实例
     */
    public static FontStyle getInstance() {
        return getInstance("宋体", 0, 12);
    }

    /**
     * 获取FontStyle实例
     * 
     * @param font
     *            字体
     * @return FontStyle实例
     */
    public static FontStyle getInstance(Font font) {
        return getInstance(font.getName(), font.getStyle(), font.getSize());
    }

    /**
     * 获取FontStyle实例
     * 
     * @param name
     *            名称
     * @param style
     *            类型
     * @param size
     *            大小
     * @return FontStyle实例
     */
    public static FontStyle getInstance(String name, int style, int size) {
        return getInstance(name, style, size, Color.black, 0, false, false, false, false);
    }

    /**
     * 获取FontStyle实例
     * 
     * @param name
     *            名称
     * @param style
     *            类型
     * @param size
     *            大小
     * @param color
     *            颜色
     * @return FontStyle实例
     */
    public static FontStyle getInstance(String name, int style, int size, Color color) {
        return getInstance(name, style, size, color, 0, false, false, false, false);
    }

    /**
     * 获取FontStyle实例
     * 
     * @param name
     *            名称
     * @param style
     *            类型
     * @param size
     *            大小
     * @param color
     *            颜色
     * @param underline
     *            下划线
     * @return FontStyle实例
     */
    public static FontStyle getInstance(String name, int style, int size, Color color, int underline) {
        return getInstance(name, style, size, color, underline, false, false, false, false);
    }

    /**
     * 获取FontStyle实例
     * 
     * @param name
     *            名称
     * @param style
     *            类型
     * @param size
     *            大小
     * @param color
     *            颜色
     * @param underline
     *            下划线
     * @param strikethrough
     *            穿透线
     * @param shadow
     *            阴影
     * @param superscript
     *            上标
     * @param subscript
     *            下标
     * @return FontStyle实例
     */
    public static FontStyle getInstance(String name, int style, int size, Color color, int underline,
            boolean strikethrough, boolean shadow, boolean superscript, boolean subscript) {
        FSK key = new FSK(name, style, size, color, underline, strikethrough, shadow, superscript, subscript);
        FontStyle fontStyle = cachedFontStyle.get(key);

        if (null != fontStyle) {
            return fontStyle;
        }

        FontStyle newStyle = new FontStyle(name, style, size, color, underline, strikethrough, shadow, superscript,
                subscript);
        cachedFontStyle.put(key, newStyle);

        return newStyle;
    }

    /**
     * 应用字体名
     * 
     * @param name
     *            字体名称
     * @return 字体样式
     */
    public FontStyle applyName(String name) {
        return getInstance(name, this.style, this.size, this.foreground, this.underline, this.strikethrough,
                this.shadow, this.superscript, this.subscript);
    }

    /**
     * 应用字体样式
     * 
     * @param style
     *            字体样式
     * @return 字体样式
     */
    public FontStyle applyStyle(int style) {
        return getInstance(this.name, style, this.size, this.foreground, this.underline, this.strikethrough,
                this.shadow, this.superscript, this.subscript);
    }

    /**
     * 应用字体大小
     * 
     * @param size
     *            字体大小
     * @return 字体样式
     */
    public FontStyle applySize(int size) {
        return getInstance(this.name, this.style, size, this.foreground, this.underline, this.strikethrough,
                this.shadow, this.superscript, this.subscript);
    }

    /**
     * 应用字体颜色
     * 
     * @param color
     *            字体颜色
     * @return 字体样式
     */
    public FontStyle applyForeground(Color color) {
        return getInstance(this.name, this.style, this.size, color, this.underline, this.strikethrough, this.shadow,
                this.superscript, this.subscript);
    }

    /**
     * 应用下划线
     * 
     * @param underline
     *            下划线样式
     * @return 字体样式
     */
    public FontStyle applyUnderline(int underline) {
        return getInstance(this.name, this.style, this.size, this.foreground, underline, this.strikethrough,
                this.shadow, this.superscript, this.subscript);
    }

    /**
     * 应用删除线
     * 
     * @param strikethrough
     *            是否删除线
     * @return 字体样式
     */
    public FontStyle applyStrikethrough(boolean strikethrough) {
        return getInstance(this.name, this.style, this.size, this.foreground, this.underline, strikethrough,
                this.shadow, this.superscript, this.subscript);
    }

    /**
     * 应用阴影
     * 
     * @param shadow
     *            是否阴影
     * @return 字体样式
     */
    public FontStyle applyShadow(boolean shadow) {
        return getInstance(this.name, this.style, this.size, this.foreground, this.underline, this.strikethrough,
                shadow, this.superscript, this.subscript);
    }

    /**
     * 应用上标
     * 
     * @param superscript
     *            是否上标
     * @return 字体样式
     */
    public FontStyle applySuperscript(boolean superscript) {
        return getInstance(this.name, this.style, this.size, this.foreground, this.underline, this.strikethrough,
                this.shadow, superscript, this.subscript);
    }

    /**
     * 应用下标
     * 
     * @param subscript
     *            是否下标
     * @return 字体样式
     */
    public FontStyle applySubscript(boolean subscript) {
        return getInstance(this.name, this.style, this.size, this.foreground, this.underline, this.strikethrough,
                this.shadow, this.superscript, subscript);
    }

    /**
     * 
     * @param name
     *            名称
     * @param style
     *            类型
     * @param size
     *            大小
     * @param color
     *            颜色
     * @param underline
     *            下划线
     * @param strikethrough
     *            穿透线
     * @param shadow
     *            阴影
     * @param superscript
     *            上标
     * @param subscript
     *            下标
     */
    private FontStyle(String name, int style, int size, Color color, int underline, boolean strikethrough,
            boolean shadow, boolean superscript, boolean subscript) {
        super(name, style, size);

        this.foreground = color;
        this.underline = underline;
        this.strikethrough = strikethrough;
        this.shadow = shadow;
        this.superscript = superscript;
        this.subscript = subscript;
    }

    /**
     * 
     * @return 字体颜色
     */
    public Color getForeground() {
        return foreground;
    }

    /**
     * 
     * @return 下滑线颜色
     */
    public int getUnderline() {
        return underline;
    }

    /**
     * 
     * @return 是否穿透性
     */
    public boolean isStrikethrough() {
        return strikethrough;
    }

    /**
     * 
     * @return 是否阴影
     */
    public boolean isShadow() {
        return shadow;
    }

    /**
     * 
     * @return 是否上标
     */
    public boolean isSuperscript() {
        return superscript;
    }

    /**
     * 
     * @return 是否下标
     */
    public boolean isSubscript() {
        return subscript;
    }

    /**
     * FontStyle键值类，用于缓存FontStyle
     */
    private static class FSK {
        private String name;
        private int style;
        private int size;
        private Color foreground;
        private int underline;
        private boolean strikethrough;
        private boolean shadow;
        private boolean superscript;
        private boolean subscript;

        FSK(String name, int style, int size, Color foregournd, int underline, boolean strikethrough, boolean shadow,
                boolean superscript, boolean subscript) {
            this.name = name;
            this.style = style;
            this.size = size;
            this.foreground = foregournd;
            this.underline = underline;
            this.strikethrough = strikethrough;
            this.shadow = shadow;
            this.superscript = superscript;
            this.subscript = subscript;
        }

        @Override
        public boolean equals(Object obj) {
            if (this == obj)
                return true;
            if (obj == null)
                return false;
            if (getClass() != obj.getClass())
                return false;
            FSK other = (FSK) obj;
            if (foreground == null) {
                if (other.foreground != null)
                    return false;
            } else if (!foreground.equals(other.foreground))
                return false;
            if (name == null) {
                if (other.name != null)
                    return false;
            } else if (!name.equals(other.name))
                return false;
            if (shadow != other.shadow)
                return false;
            if (size != other.size)
                return false;
            if (strikethrough != other.strikethrough)
                return false;
            if (style != other.style)
                return false;
            if (subscript != other.subscript)
                return false;
            if (superscript != other.superscript)
                return false;
            if (underline != other.underline)
                return false;
            return true;
        }

        @Override
        public int hashCode() {
            final int prime = 31;
            int result = 1;
            result = prime * result + ((foreground == null) ? 0 : foreground.hashCode());
            result = prime * result + ((name == null) ? 0 : name.hashCode());
            result = prime * result + (shadow ? 1231 : 1237);
            result = prime * result + size;
            result = prime * result + (strikethrough ? 1231 : 1237);
            result = prime * result + style;
            result = prime * result + (subscript ? 1231 : 1237);
            result = prime * result + (superscript ? 1231 : 1237);
            result = prime * result + underline;
            return result;
        }
    }
}
